package xyz.yuanjilu.controller;

import com.riversoft.weixin.common.decrypt.AesException;
import com.riversoft.weixin.common.decrypt.MessageDecryption;
import com.riversoft.weixin.common.decrypt.SHA1;
import com.riversoft.weixin.common.event.EventRequest;
import com.riversoft.weixin.common.event.EventType;
import com.riversoft.weixin.common.exception.WxRuntimeException;
import com.riversoft.weixin.common.message.MsgType;
import com.riversoft.weixin.common.message.XmlMessageHeader;
import com.riversoft.weixin.common.message.xml.TextXmlMessage;
import com.riversoft.weixin.common.request.ImageRequest;
import com.riversoft.weixin.common.request.LocationRequest;
import com.riversoft.weixin.common.request.TextRequest;
import com.riversoft.weixin.common.request.VoiceRequest;
import com.riversoft.weixin.mp.base.AppSetting;
import com.riversoft.weixin.mp.care.CareMessages;
import com.riversoft.weixin.mp.message.MpXmlMessages;
import com.riversoft.weixin.mp.user.Users;

import xyz.yuanjilu.annotation.SysLog;
import xyz.yuanjilu.entity.WeixinConfigEntity;
import xyz.yuanjilu.entity.WeixinMediaEntity;
import xyz.yuanjilu.plug.MPPlug;
import xyz.yuanjilu.service.WeixinConfigService;
import xyz.yuanjilu.service.WeixinMediaService;

import java.io.IOException;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

/**
 * Created by exizhai on 10/7/2015.
 */
@Controller
public class WxCallbackController {

    private static Logger logger = LoggerFactory.getLogger(WxCallbackController.class);
    @Autowired
    private WeixinConfigService weixinConfigService;
    @Autowired
    private WeixinMediaService weixinMediaService;

    /**
     * 公众号回调接口
     * 这里为了演示方便使用单个固定URL，实际使用的时候一个一个系统可能有多个公众号，这样的话需要有个分发逻辑：
     * 比如callback url可以定义为  /wx/mp/[公众号的appId]，通过appId构造不同的AppSetting
     *
     * @param signature
     * @param msg_signature
     * @param timestamp
     * @param nonce
     * @param echostr
     * @param encrypt_type
     * @param content
     * @return
     * @throws IOException 
     */
    @SysLog("微信接入回调")
    @RequestMapping(value={"/wx/mp/{weixinCode}"},method={RequestMethod.GET})
    @ResponseBody
    public String mpGet(@RequestParam(value="signature", required = false) String signature,
                     @RequestParam(value="msg_signature", required = false) String msg_signature,
                     @RequestParam(value="timestamp", required = false) String timestamp,
                     @RequestParam(value="nonce", required = false) String nonce,
                     @RequestParam(value="echostr", required = false) String echostr,
                     @RequestParam(value="encrypt_type", required = false) String encrypt_type,
                     @RequestBody(required = false) String content,@PathVariable("weixinCode") String weixinCode,HttpServletResponse response) throws IOException {

        logger.info("signature={}, msg_signature={}, timestamp={}, nonce={}, echostr={}, encrypt_type={}", signature, msg_signature, timestamp, nonce, echostr, encrypt_type);
        AppSetting appSetting = weixinConfigService.getAppSetting(weixinCode);
        try {
            if(!SHA1.getSHA1(appSetting.getToken(), timestamp, nonce).equals(signature)) {
                logger.warn("非法请求.");
                return "非法请求.";
            }
        } catch (AesException e) {
            logger.error("check signature failed:", e);
            return "非法请求.";
        }
        return echostr;
    }
    @SysLog("微信消息回调")
    @RequestMapping(value={"/wx/mp/{weixinCode}"},method={RequestMethod.POST})
    @ResponseBody
    public String mpPost(@RequestParam(value="signature", required = false) String signature,
                     @RequestParam(value="msg_signature", required = false) String msg_signature,
                     @RequestParam(value="timestamp", required = false) String timestamp,
                     @RequestParam(value="nonce", required = false) String nonce,
                     @RequestParam(value="echostr", required = false) String echostr,
                     @RequestParam(value="encrypt_type", required = false) String encrypt_type,
                     @RequestBody(required = false) String content,@PathVariable("weixinCode") String weixinCode) {

        logger.info("signature={}, msg_signature={}, timestamp={}, nonce={}, echostr={}, encrypt_type={}, content={}, weixinCode={}", signature, msg_signature, timestamp, nonce, echostr, encrypt_type,content,weixinCode);
        WeixinConfigEntity weixinConfig = weixinConfigService.queryObjectByWeixinCode(weixinCode);
        AppSetting appSetting = weixinConfigService.getAppSetting(weixinConfig);

        XmlMessageHeader xmlRequest = null;
        if("aes".equals(encrypt_type)) {
            try {
                MessageDecryption messageDecryption = new MessageDecryption(appSetting.getToken(), appSetting.getAesKey(), appSetting.getAppId());
                xmlRequest = MpXmlMessages.fromXml(messageDecryption.decrypt(msg_signature, timestamp, nonce, content));
                XmlMessageHeader xmlResponse = mpDispatch(xmlRequest,appSetting,weixinConfig);

                if(xmlResponse != null) {
                    try {
                        return messageDecryption.encrypt(MpXmlMessages.toXml(xmlResponse), timestamp, nonce);
                    } catch (WxRuntimeException e) {

                    }
                }
            } catch (AesException e) {
            }
        } else {
            xmlRequest = MpXmlMessages.fromXml(content);
            XmlMessageHeader xmlResponse = mpDispatch(xmlRequest,appSetting,weixinConfig);
            if(xmlResponse != null) {
                try {
                    return MpXmlMessages.toXml(xmlResponse);
                } catch (WxRuntimeException e) {
                }
            }
        }

        return "";
    }

    private XmlMessageHeader mpDispatch(XmlMessageHeader xmlRequest,AppSetting appSetting,WeixinConfigEntity weixinConfig) {
    	XmlMessageHeader xmlResponse=new TextXmlMessage();;
    	xmlResponse.setToUser(xmlRequest.getFromUser());
        MsgType msgType = xmlRequest.getMsgType();
        try {
        	WeixinMediaEntity weixinMedia=new WeixinMediaEntity();
        	
			weixinMedia.setWeixinId(weixinConfig.getId());
			weixinMedia.setFromUserId(xmlRequest.getFromUser());
			weixinMedia.setMediaType(xmlRequest.getMsgType().name());
			
        	if (xmlRequest instanceof VoiceRequest) {
    			VoiceRequest request = (VoiceRequest) xmlRequest;
    			weixinMedia.setId(request.getMediaId());
    			//特殊设置
    			weixinMedia.setMediaRecognition(request.getRecognition());
    			weixinMediaService.saveOrUpdate(weixinMedia);
    		}else if (xmlRequest instanceof ImageRequest) {
    			ImageRequest request = (ImageRequest) xmlRequest;
    			String imgurl=request.getPicUrl();
    			weixinMedia.setId(request.getMediaId());
    			//特殊设置
    			weixinMedia.setMediaPicUrl(imgurl);
    			weixinMediaService.saveOrUpdate(weixinMedia);
    		}else if (xmlRequest instanceof LocationRequest) {
				LocationRequest request = (LocationRequest) xmlRequest;
				weixinMedia.setId(request.getX()+"-"+request.getY());
				//特殊设置
    			weixinMedia.setMediaLabel(request.getLabel());
    			weixinMediaService.saveOrUpdate(weixinMedia);
				
			}
        	
        	if(weixinConfigService.superXmlMessageHeader(xmlRequest, weixinConfig)) {
                if (xmlRequest instanceof EventRequest) {
                    EventRequest eventRequest = (EventRequest) xmlRequest;
                    EventType eventType = eventRequest.getEventType();
    				logger.info("事件请求[{}]", eventType.name());
                } else {
                    logger.info("消息请求[{}]", msgType.name());
                }
                xmlResponse=weixinConfigService.handle(xmlRequest.getFromUser(), xmlRequest, xmlResponse, weixinConfig);
            } else {
            	xmlResponse=weixinConfigService.getErrorMessage(xmlRequest,weixinConfig);
                logger.warn("Duplicated message: {} @ {}", msgType, xmlRequest.getFromUser());
            }
		} catch (Exception e) {
			 logger.error("mpDispatch error", e);
			 TextXmlMessage toMessage=new TextXmlMessage();
	    	 toMessage.setToUser(xmlRequest.getFromUser());
			 toMessage.setContent("出现异常请重试");
			 xmlResponse=toMessage;
		}
		
		
        //需要同步返回消息（被动回复）给用户则构造一个XmlMessageHeader类型，比较鸡肋，因为处理逻辑如果比较复杂响应太慢会影响用户感知，建议直接返回null；
        //要发送消息给用户可以参考上面的例子使用客服消息接口进行异步发送
        return xmlResponse;
    }
}
